package com.cskaoyan.javase.object._6clone._0introduction;

/**
 * Object类当中的clone方法
 * 1.方法的声明和方法体
 *  protected native Object clone() throws CloneNotSupportedException;
 *  首先需要注意的是,访问权限修饰符,protected:
 *      a.同包下任意访问
 *      b.不同包下,在子类中,创建子类自身对象才能够访问
 *  并且它是一个本地方法,没有方法体
 *  Object表示该方法的返回值是一个对象
 *  它不需要参数,是一个无参的方法
 *  throws CloneNotSupportedException 这是方法抛出异常的声明,后面再说,这里可以无视它
 *
 *  2.clone方法的作用
 *      clone就是克隆,Java中的克隆是通过一个对象,获取一个和原先对象完全相同,但又相对独立的对象
 *      说白了,获取一个和原先对象,成员变量取值完全一样,但又不是同一个对象(Object类当中的默认实现)
 *      在实际开发中,如果你有获取一个相同对象的需求,就可以使用clone方法
 *      clone方法是完全不同于new对象的一种创建对象的方式,不依赖于构造器,依赖于本地方法创建对象
 *
 * 3.clone方法的使用步骤
 *      a.默认情况下,clone方法是protected修饰的.这意味着,某个类只能在自身类中调用自身的clone方法
 *          这叫自己克隆自己,一般来说意义不大
 *          所以第一步需要突破访问权限的限制
 *          需要重写clone方法的访问权限
 *
 *      b.(选做,非必须) clone方法的默认实现,会得到一个和原先对象,类型一致,成员变量取值完全一致的独立对象
 *          所以重写返回值类型,方便方法调用
 *
 *      c.一个类的对象,如果直接做克隆操作,会抛出异常CloneNotSupportedException(不支持克隆异常)程序终止
 *          这是因为Java中的一个对象如果想做克隆操作,必须首先该类要实现接口Cloneable(能够克隆)
 *          所以在做克隆之前,需要这个类实现java.lang.Cloneable接口,这步是必须的
 *
 * 以上,就完成了Object类当中默认的克隆操作,得到了一个和原先对象完全独立,但属性取值一样的对象
 *
 * 细节问题:
 *      1.clone方法和new对象是平行的两种创建对象方式,clone不会调用构造方法
 *      2.Cloneable接口说明,它是一个比较特殊的接口,它是一个空接口,它完全没有抽象方法.
 *          空接口的作用,它是一种标记接口
 *          实现它虽然不能新增成员,但是能够允许做某些操作
 *
 *      3.clone方法不是final修饰的,如果确有必须,是可以重写的(这种需求很少见,一般使用Object类的默认实现就足够了)
 *      重写clone方法的原则:
 *          1. x.clone() != x 为 true
 *          2. x.clone().getClass() == x.getClass() 一般也为true
 *          3. x.clone().equals(x) 一般情况下也为true
 *
 * 上述规定告诉我们：
 *          1. 克隆必须是一个新的独立的对象
 *          2. 克隆最好不要改变数据类型，除非你真的有需要。
 *          3. 克隆后的两个对象调用equals方法，应该返回true。
 *          前提是，必须按照成员变量的取值重写equals方法。
 *          如果equals方法没有重写,依据地址比较两个对象,那结果肯定是false.
 *
 * @since 16:05
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student s1 = new Student(18, 100);
        // 重写访问权限之前报错 'clone()' has protected access in 'java.lang.Object' 因为没权限
        // 重写访问权限之后报错 Unhandled exception: java.lang.CloneNotSupportedException 因为异常,不用管,直接alt+回车,修正错误即可
        Student cloneStu = s1.clone();
        // clone得到的是独立对象,所以返回false
        System.out.println(s1 == cloneStu);
        System.out.println(s1.age == cloneStu.age);
        System.out.println(s1.score == cloneStu.score);
    }
}

class Student implements MyCloneable{
    int age;
    double score;

    public Student() {
        // System.out.println("xxx");
    }

    public Student(int age, double score) {
        this.age = age;
        this.score = score;
        // System.out.println("xxx");
    }

    /*
        父子类中,重写方法的,返回值类型 不一定保持一致
        如果父类方法,返回一个父类类型
        那么子类方法,可以返回一个子类类型
     */
    @Override
    protected Student clone() throws CloneNotSupportedException {
        return ((Student) super.clone());
    }
}
/*
    Cloneable是顶层父接口
    MyCloneable是继承父接口的子接口
    Student又实现了子接口
     Student和Cloneable是"爷爷"和"孙子"
 */
interface MyCloneable extends Cloneable{}